home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 2.iso / STUTTGART / LANG / C / GCC / V2-4-5 / GPPLIBSR00 / cc / sbufvform < prev    next >
Text File  |  1993-12-08  |  33KB  |  866 lines

  1. /*
  2.  * Copyright (c) 1990 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by the University of California, Berkeley.  The name of the
  11.  * University may not be used to endorse or promote products derived
  12.  * from this software without specific prior written permission.
  13.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16.  */
  17.  
  18.  
  19. #if defined(LIBC_SCCS) && !defined(lint)
  20. static char sccsid[] = "%W% (Berkeley) %G%";
  21. #endif /* LIBC_SCCS and not lint */
  22.  
  23. /*
  24.  * Actual printf innards.
  25.  *
  26.  * This code is large and complicated...
  27.  */
  28.  
  29. extern "C"
  30.   {
  31.   #include <sys/types.h>
  32.   #include <string.h>
  33.   #include <stdarg.h>
  34.   }
  35.   
  36. #include "ioprivate.h"
  37.  
  38.  
  39. /*
  40.  * Define FLOATING_POINT to get floating point.
  41.  */
  42. #ifndef NO_FLOATING_POINT
  43. #define FLOATING_POINT
  44. #endif
  45.  
  46. /* end of configuration stuff */
  47.  
  48.  
  49. /*
  50.  * Helper class and function for `fprintf to unbuffered': creates a
  51.  * temporary buffer.  We only work on write-only files; this avoids
  52.  * worries about ungetc buffers and so forth.
  53.  */
  54.  
  55. class help_streambuf : public backupbuf {
  56.   public:
  57.     char *buffer;
  58.     int buf_size;
  59.     streambuf *sb;
  60.     help_streambuf(streambuf *sbuf, char *buf, int n) {
  61.         sb = sbuf; buffer = buf; buf_size = n;
  62.         setp(buffer, buffer+buf_size); }
  63.     ~help_streambuf();
  64.     virtual int overflow(int c = EOF);
  65. };
  66.  
  67. int help_streambuf::overflow(int c)
  68. {
  69.     int used = pptr() - pbase();
  70.     if (used) {
  71.         sb->sputn(pbase(), used);
  72.         pbump(-used);
  73.     }
  74.     if (c == EOF || buf_size == 0)
  75.         return sb->overflow(c);
  76.     return sputc(c);
  77. }
  78. help_streambuf::~help_streambuf()
  79. {
  80.     int used = pptr() - pbase();
  81.     if (used) {
  82.         sb->sputn(pbase(), used);
  83.         pbump(-used);
  84.     }
  85. }
  86.  
  87. int help_vform(streambuf *sb, char const *fmt0, va_list ap)
  88. {
  89.     char buf[_G_BUFSIZ];
  90.     help_streambuf helper(sb, buf, _G_BUFSIZ);
  91.     return helper.vform(fmt0, ap);
  92. }
  93.  
  94. #ifdef FLOATING_POINT
  95.  
  96. #include "floatio.h"
  97. #define BUF             (MAXEXP+MAXFRACT+1)     /* + decimal point */
  98. #define DEFPREC         6
  99. extern "C" double modf(double, double*);
  100.  
  101. #else /* no FLOATING_POINT */
  102.  
  103. #define BUF             40
  104.  
  105. #endif /* FLOATING_POINT */
  106.  
  107.  
  108. /*
  109.  * Macros for converting digits to letters and vice versa
  110.  */
  111. #define to_digit(c)     ((c) - '0')
  112. #define is_digit(c)     ((unsigned)to_digit(c) <= 9)
  113. #define to_char(n)      ((n) + '0')
  114.  
  115. /*
  116.  * Flags used during conversion.
  117.  */
  118. #define LONGINT         0x01            /* long integer */
  119. #define LONGDBL         0x02            /* long double; unimplemented */
  120. #define SHORTINT        0x04            /* short integer */
  121. #define ALT             0x08            /* alternate form */
  122. #define LADJUST         0x10            /* left adjustment */
  123. #define ZEROPAD         0x20            /* zero (as opposed to blank) pad */
  124. #define HEXPREFIX       0x40            /* add 0x or 0X prefix */
  125.  
  126. int streambuf::vform(char const *fmt0, _G_va_list ap)
  127. {
  128.         register const char *fmt; /* format string */
  129.         register int ch;        /* character from fmt */
  130.         register int n;         /* handy integer (short term usage) */
  131.         register char *cp;      /* handy char pointer (short term usage) */
  132.         const char *fmark;      /* for remembering a place in fmt */
  133.         register int flags;     /* flags as above */
  134.         int ret;                /* return value accumulator */
  135.         int width;              /* width from format (%8d), or 0 */
  136.         int prec;               /* precision from format (%.3d), or -1 */
  137.         char sign;              /* sign prefix (' ', '+', '-', or \0) */
  138. #ifdef FLOATING_POINT
  139.         int softsign;           /* temporary negative sign for floats */
  140.         double _double;         /* double precision arguments %[eEfgG] */
  141. #ifndef USE_DTOA
  142.         int fpprec;             /* `extra' floating precision in [eEfgG] */
  143. #endif
  144. #endif
  145.         unsigned long _ulong;   /* integer arguments %[diouxX] */
  146.         enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
  147.         int dprec;              /* a copy of prec if [diouxX], 0 otherwise */
  148.         int dpad;               /* extra 0 padding needed for integers */
  149.         int fieldsz;            /* field size expanded by sign, dpad etc */
  150.         // The initialization of 'size' is to suppress a warning that
  151.         // 'size' might be used unitialized.  It seems gcc can't
  152.         // quite grok this spaghetti code ...
  153.         int size = 0;           /* size of converted field or string */
  154.         char buf[BUF];          /* space for %c, %[diouxX], %[eEfgG] */
  155.         char ox[2];             /* space for 0x hex-prefix */
  156.  
  157.         /*
  158.          * Choose PADSIZE to trade efficiency vs size.  If larger
  159.          * printf fields occur frequently, increase PADSIZE (and make
  160.          * the initialisers below longer).
  161.          */
  162. #define PADSIZE 16              /* pad chunk size */
  163.         static char const blanks[PADSIZE] =
  164.          {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
  165.         static char const zeroes[PADSIZE] =
  166.          {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
  167.  
  168.         /*
  169.          * BEWARE, these `goto error' on error, and PAD uses `n'.
  170.          */
  171. #define PRINT(ptr, len) \
  172.   do { if (sputn(ptr, len) != len) goto error; } while (0)
  173. #if 1
  174. #define PAD_SP(howmany) if (padn(' ', howmany) < 0) goto error;
  175. #define PAD_0(howmany) if (padn('0', howmany) < 0) goto error;
  176. #else
  177. #define PAD(howmany, with) { \
  178.         if ((n = (howmany)) > 0) { \
  179.                 while (n > PADSIZE) { \
  180.                         PRINT(with, PADSIZE); \
  181.                         n -= PADSIZE; \
  182.                 } \
  183.                 PRINT(with, n); \
  184.         } \
  185. }
  186. #define PAD_SP(howmany) PAD(howmany, blanks)
  187. #define PAD_0(howmany) PAD(howmany, zeroes)
  188. #endif
  189.  
  190.         /*
  191.          * To extend shorts properly, we need both signed and unsigned
  192.          * argument extraction methods.
  193.          */
  194. #define SARG() \
  195.         (flags&LONGINT ? va_arg(ap, long) : \
  196.             flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
  197.             (long)va_arg(ap, int))
  198. #define UARG() \
  199.         (flags&LONGINT ? va_arg(ap, unsigned long) : \
  200.             flags&SHORTINT ? (unsigned long)(unsigned short)va_arg(ap, int) : \
  201.             (unsigned long)va_arg(ap, unsigned int))
  202.  
  203.         /* optimise cerr (and other unbuffered Unix files) */
  204.         if (unbuffered())
  205.             return help_vform(this, fmt0, ap);
  206.  
  207.         fmt = fmt0;
  208.         ret = 0;
  209.  
  210.         /*
  211.          * Scan the format for conversions (`%' character).
  212.          */
  213.         for (;;) {
  214.                 for (fmark = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
  215.                         /* void */;
  216.                 if ((n = fmt - fmark) != 0) {
  217.                         PRINT(fmark, n);
  218.                         ret += n;
  219.                 }
  220.                 if (ch == '\0')
  221.                         goto done;
  222.                 fmt++;          /* skip over '%' */
  223.  
  224.                 flags = 0;
  225.                 dprec = 0;
  226. #if defined(FLOATING_POINT) && !defined (USE_DTOA)
  227.                 fpprec = 0;
  228. #endif
  229.                 width = 0;
  230.                 prec = -1;
  231.                 sign = '\0';
  232.  
  233. rflag:          ch = *fmt++;
  234. reswitch:       switch (ch) {
  235.                 case ' ':
  236.                         /*
  237.                          * ``If the space and + flags both appear, the space
  238.                          * flag will be ignored.''
  239.                          *      -- ANSI X3J11
  240.                          */
  241.                         if (!sign)
  242.                                 sign = ' ';
  243.                         goto rflag;
  244.                 case '#':
  245.                         flags |= ALT;
  246.                         goto rflag;
  247.                 case '*':
  248.                         /*
  249.                          * ``A negative field width argument is taken as a
  250.                          * - flag followed by a positive field width.''
  251.                          *      -- ANSI X3J11
  252.                          * They don't exclude field widths read from args.
  253.                          */
  254.                         if ((width = va_arg(ap, int)) >= 0)
  255.                                 goto rflag;
  256.                         width = -width;
  257.                         /* FALLTHROUGH */
  258.                 case '-':
  259.                         flags |= LADJUST;
  260.                         flags &= ~ZEROPAD; /* '-' disables '0' */
  261.                         goto rflag;
  262.                 case '+':
  263.                         sign = '+';
  264.                         goto rflag;
  265.                 case '.':
  266.                         if ((ch = *fmt++) == '*') {
  267.                                 n = va_arg(ap, int);
  268.                                 prec = n < 0 ? -1 : n;
  269.                                 goto rflag;
  270.                         }
  271.                         n = 0;
  272.                         while (is_digit(ch)) {
  273.                                 n = 10 * n + to_digit(ch);
  274.                                 ch = *fmt++;
  275.                         }
  276.                         prec = n < 0 ? -1 : n;
  277.                         goto reswitch;
  278.                 case '0':
  279.                         /*
  280.                          * ``Note that 0 is taken as a flag, not as the
  281.                          * beginning of a field width.''
  282.                          *      -- ANSI X3J11
  283.                          */
  284.                         if (!(flags & LADJUST))
  285.                             flags |= ZEROPAD; /* '-' disables '0' */
  286.                         goto rflag;
  287.                 case '1': case '2': case '3': case '4':
  288.                 case '5': case '6': case '7': case '8': case '9':
  289.                         n = 0;
  290.                         do {
  291.                                 n = 10 * n + to_digit(ch);
  292.                                 ch = *fmt++;
  293.                         } while (is_digit(ch));
  294.                         width = n;
  295.                         goto reswitch;
  296. #ifdef FLOATING_POINT
  297.                 case 'L':
  298.                         flags |= LONGDBL;
  299.                         goto rflag;
  300. #endif
  301.                 case 'h':
  302.                         flags |= SHORTINT;
  303.                         goto rflag;
  304.                 case 'l':
  305.                         flags |= LONGINT;
  306.                         goto rflag;
  307.                 case 'c':
  308.                         *(cp = buf) = va_arg(ap, int);
  309.                         size = 1;
  310.                         sign = '\0';
  311.                         break;
  312.                 case 'D':
  313.                         flags |= LONGINT;
  314.                         /*FALLTHROUGH*/
  315.                 case 'd':
  316.                 case 'i':
  317.                         _ulong = SARG();
  318.                         if ((long)_ulong < 0) {
  319.                                 _ulong = -_ulong;
  320.                                 sign = '-';
  321.                         }
  322.                         base = DEC;
  323.                         goto number;
  324. #ifdef FLOATING_POINT
  325.                 case 'e':
  326.                 case 'E':
  327.                 case 'f':
  328.                 case 'F':
  329.                 case 'g':
  330.                 case 'G':
  331.                         _double = va_arg(ap, double);
  332. #ifdef USE_DTOA
  333.                         {
  334.                             ios::fmtflags fmt_flags = 0;
  335.                             int fill = ' ';
  336.                             if (flags & ALT)
  337.                                 fmt_flags |= ios::showpoint;
  338.                             if (flags & LADJUST)
  339.                                 fmt_flags |= ios::left;
  340.                             else if (flags & ZEROPAD)
  341.                                 fmt_flags |= ios::internal, fill = '0';
  342.                             n = __outfloat(_double, this, ch, width,
  343.                                            prec < 0 ? DEFPREC : prec,
  344.                                            fmt_flags, sign, fill);
  345.                             if (n < 0)
  346.                                 goto error;
  347.                             ret += n;
  348.                         }
  349.                         // CHECK ERROR!
  350.                         continue;
  351. #else
  352.                         /*
  353.                          * don't do unrealistic precision; just pad it with
  354.                          * zeroes later, so buffer size stays rational.
  355.                          */
  356.                         if (prec > MAXFRACT) {
  357.                                 if ((ch != 'g' && ch != 'G') || (flags&ALT))
  358.                                         fpprec = prec - MAXFRACT;
  359.                                 prec = MAXFRACT;
  360.                         } else if (prec == -1)
  361.                                 prec = DEFPREC;
  362.                         // __cvt_double may have to round up before the
  363.                         // "start" of its buffer, i.e.
  364.                         // ``intf("%.2f", (double)9.999);'';
  365.                         // if the first character is still NUL, it did.
  366.                         // softsign avoids negative 0 if _double < 0 but
  367.                         // no significant digits will be shown.
  368.                         cp = buf;
  369.                         *cp = '\0';
  370.                         size = __cvt_double(_double, prec, flags, &softsign,
  371.                                             ch, cp, buf + sizeof(buf));
  372.                         if (softsign)
  373.                                 sign = '-';
  374.                         if (*cp == '\0')
  375.                                 cp++;
  376.                         break;
  377. #endif
  378. #endif /* FLOATING_POINT */
  379.                 case 'n':
  380.                         if (flags & LONGINT)
  381.                                 *va_arg(ap, long *) = ret;
  382.                         else if (flags & SHORTINT)
  383.                                 *va_arg(ap, short *) = ret;
  384.                         else
  385.                                 *va_arg(ap, int *) = ret;
  386.                         continue;       /* no output */
  387.                 case 'O':
  388.                         flags |= LONGINT;
  389.                         /*FALLTHROUGH*/
  390.                 case 'o':
  391.                         _ulong = UARG();
  392.                         base = OCT;
  393.                         goto nosign;
  394.                 case 'p':
  395.                         /*
  396.                          * ``The argument shall be a pointer to void.  The
  397.                          * value of the pointer is converted to a sequence
  398.                          * of printable characters, in an implementation-
  399.                          * defined manner.''
  400.                          *      -- ANSI X3J11
  401.                          */
  402.                         /* NOSTRICT */
  403.                         _ulong = (unsigned long)va_arg(ap, void *);
  404.                         base = HEX;
  405.                         flags |= HEXPREFIX;
  406.                         ch = 'x';
  407.                         goto nosign;
  408.                 case 's':
  409.                         if ((cp = va_arg(ap, char *)) == NULL)
  410.                                 cp = "(null)";
  411.                         if (prec >= 0) {
  412.                                 /*
  413.                                  * can't use strlen; can only look for the
  414.                                  * NUL in the first `prec' characters, and
  415.                                  * strlen() will go further.
  416.                                  */
  417.                                 char *p = (char*)memchr(cp, 0, prec);
  418.  
  419.                                 if (p != NULL) {
  420.                                         size = p - cp;
  421.                                         if (size > prec)
  422.                                                 size = prec;
  423.                                 } else
  424.                                         size = prec;
  425.                         } else
  426.                                 size = strlen(cp);
  427.                         sign = '\0';
  428.                         break;
  429.                 case 'U':
  430.                         flags |= LONGINT;
  431.                         /*FALLTHROUGH*/
  432.                 case 'u':
  433.                         _ulong = UARG();
  434.                         base = DEC;
  435.                         goto nosign;
  436.                 case 'X':
  437.                 case 'x':
  438.                         _ulong = UARG();
  439.                         base = HEX;
  440.                         /* leading 0x/X only if non-zero */
  441.                         if (flags & ALT && _ulong != 0)
  442.                                 flags |= HEXPREFIX;
  443.  
  444.                         /* unsigned conversions */
  445. nosign:                 sign = '\0';
  446.                         /*
  447.                          * ``... diouXx conversions ... if a precision is
  448.                          * specified, the 0 flag will be ignored.''
  449.                          *      -- ANSI X3J11
  450.                          */
  451. number:                 if ((dprec = prec) >= 0)
  452.                                 flags &= ~ZEROPAD;
  453.  
  454.                         /*
  455.                          * ``The result of converting a zero value with an
  456.                          * explicit precision of zero is no characters.''
  457.                          *      -- ANSI X3J11
  458.                          */
  459.                         cp = buf + BUF;
  460.                         if (_ulong != 0 || prec != 0) {
  461.                                 char *xdigs; /* digits for [xX] conversion */
  462.                                 /*
  463.                                  * unsigned mod is hard, and unsigned mod
  464.                                  * by a constant is easier than that by
  465.                                  * a variable; hence this switch.
  466.                                  */
  467.                                 switch (base) {
  468.                                 case OCT:
  469.                                         do {
  470.                                                 *--cp = to_char(_ulong & 7);
  471.                                                 _ulong >>= 3;
  472.                                         } while (_ulong);
  473.                                         /* handle octal leading 0 */
  474.                                         if (flags & ALT && *cp != '0')
  475.                                                 *--cp = '0';
  476.                                         break;
  477.  
  478.                                 case DEC:
  479.                                         /* many numbers are 1 digit */
  480.                                         while (_ulong >= 10) {
  481.                                                 *--cp = to_char(_ulong % 10);
  482.                                                 _ulong /= 10;
  483.                                         }
  484.                                         *--cp = to_char(_ulong);
  485.                                         break;
  486.  
  487.                                 case HEX:
  488.                                         if (ch == 'X')
  489.                                             xdigs = "0123456789ABCDEF";
  490.                                         else /* ch == 'x' || ch == 'p' */
  491.                                             xdigs = "0123456789abcdef";
  492.                                         do {
  493.                                                 *--cp = xdigs[_ulong & 15];
  494.                                                 _ulong >>= 4;
  495.                                         } while (_ulong);
  496.                                         break;
  497.  
  498.                                 default:
  499.                                         cp = "bug in vform: bad base";
  500.                                         goto skipsize;
  501.                                 }
  502.                         }
  503.                         size = buf + BUF - cp;
  504.                 skipsize:
  505.                         break;
  506.                 default:        /* "%?" prints ?, unless ? is NUL */
  507.                         if (ch == '\0')
  508.                                 goto done;
  509.                         /* pretend it was %c with argument ch */
  510.                         cp = buf;
  511.                         *cp = ch;
  512.                         size = 1;
  513.                         sign = '\0';
  514.                         break;
  515.                 }
  516.  
  517.                 /*
  518.                  * All reasonable formats wind up here.  At this point,
  519.                  * `cp' points to a string which (if not flags&LADJUST)
  520.                  * should be padded out to `width' places.  If
  521.                  * flags&ZEROPAD, it should first be prefixed by any
  522.                  * sign or other prefix; otherwise, it should be blank
  523.                  * padded before the prefix is emitted.  After any
  524.                  * left-hand padding and prefixing, emit zeroes
  525.                  * required by a decimal [diouxX] precision, then print
  526.                  * the string proper, then emit zeroes required by any
  527.                  * leftover floating precision; finally, if LADJUST,
  528.                  * pad with blanks.
  529.                  */
  530.  
  531.                 /*
  532.                  * compute actual size, so we know how much to pad.
  533.                  */
  534. #if defined(FLOATING_POINT) && !defined (USE_DTOA)
  535.                 fieldsz = size + fpprec;
  536. #else
  537.                 fieldsz = size;
  538. #endif
  539.                 dpad = dprec - size;
  540.                 if (dpad < 0)
  541.                     dpad = 0;
  542.  
  543.                 if (sign)
  544.                         fieldsz++;
  545.                 else if (flags & HEXPREFIX)
  546.                         fieldsz += 2;
  547.                 fieldsz += dpad;
  548.  
  549.                 /* right-adjusting blank padding */
  550.                 if ((flags & (LADJUST|ZEROPAD)) == 0)
  551.                         PAD_SP(width - fieldsz);
  552.  
  553.                 /* prefix */
  554.                 if (sign) {
  555.                         PRINT(&sign, 1);
  556.                 } else if (flags & HEXPREFIX) {
  557.                         ox[0] = '0';
  558.                         ox[1] = ch;
  559.                         PRINT(ox, 2);
  560.                 }
  561.  
  562.                 /* right-adjusting zero padding */
  563.                 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
  564.                         PAD_0(width - fieldsz);
  565.  
  566.                 /* leading zeroes from decimal precision */
  567.                 PAD_0(dpad);
  568.  
  569.                 /* the string or number proper */
  570.                 PRINT(cp, size);
  571.  
  572. #if defined(FLOATING_POINT) && !defined (USE_DTOA)
  573.                 /* trailing f.p. zeroes */
  574.                 PAD_0(fpprec);
  575. #endif
  576.  
  577.                 /* left-adjusting padding (always blank) */
  578.                 if (flags & LADJUST)
  579.                         PAD_SP(width - fieldsz);
  580.  
  581.                 /* finally, adjust ret */
  582.                 ret += width > fieldsz ? width : fieldsz;
  583.  
  584.         }
  585. done:
  586.         return ret;
  587. error:
  588.         return EOF;
  589.         /* NOTREACHED */
  590. }
  591.  
  592. #if defined(FLOATING_POINT) && !defined(USE_DTOA)
  593.  
  594. static char *exponent(register char *p, register int exp, int fmtch)
  595. {
  596.         register char *t;
  597.         char expbuf[MAXEXP];
  598.  
  599.         *p++ = fmtch;
  600.         if (exp < 0) {
  601.                 exp = -exp;
  602.                 *p++ = '-';
  603.         }
  604.         else
  605.                 *p++ = '+';
  606.         t = expbuf + MAXEXP;
  607.         if (exp > 9) {
  608.                 do {
  609.                         *--t = to_char(exp % 10);
  610.                 } while ((exp /= 10) > 9);
  611.                 *--t = to_char(exp);
  612.                 for (; t < expbuf + MAXEXP; *p++ = *t++);
  613.         }
  614.         else {
  615.                 *p++ = '0';
  616.                 *p++ = to_char(exp);
  617.         }
  618.         return (p);
  619. }
  620.  
  621. static char * round(double fract, int *exp,
  622.                     register char *start, register char *end,
  623.                     char ch, int *signp)
  624. {
  625.         double tmp;
  626.  
  627.         if (fract)
  628.         (void)modf(fract * 10, &tmp);
  629.         else
  630.                 tmp = to_digit(ch);
  631.         if (tmp > 4)
  632.                 for (;; --end) {
  633.                         if (*end == '.')
  634.                                 --end;
  635.                         if (++*end <= '9')
  636.                                 break;
  637.                         *end = '0';
  638.                         if (end == start) {
  639.                                 if (exp) {      /* e/E; increment exponent */
  640.                                         *end = '1';
  641.                                         ++*exp;
  642.                                 }
  643.                                 else {          /* f; add extra digit */
  644.                                 *--end = '1';
  645.                                 --start;
  646.                                 }
  647.                                 break;
  648.                         }
  649.                 }
  650. #if 0
  651.         /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
  652.         else if (*signp == '-')
  653.                 for (;; --end) {
  654.                         if (*end == '.')
  655.                                 --end;
  656.                         if (*end != '0')
  657.                                 break;
  658.                         if (end == start)
  659.                                 *signp = 0;
  660.                 }
  661. #endif
  662.         return (start);
  663. }
  664.  
  665. int __cvt_double(double number, register int prec, int flags, int *signp,
  666.                  int fmtch, char *startp, char *endp)
  667. {
  668.         register char *p, *t;
  669.         register double fract;
  670.         int dotrim = 0, expcnt, gformat = 0;
  671.         double integer, tmp;
  672.  
  673.         expcnt = 0;
  674.         if (number < 0) {
  675.                 number = -number;
  676.                 *signp = '-';
  677.         } else
  678.                 *signp = 0;
  679.  
  680.  
  681.         fract = modf(number, &integer);
  682.  
  683.         /* get an extra slot for rounding. */
  684.         t = ++startp;
  685.  
  686.         /*
  687.          * get integer portion of number; put into the end of the buffer; the
  688.          * .01 is added for modf(356.0 / 10, &integer) returning .59999999...
  689.          */
  690.         for (p = endp - 1; integer; ++expcnt) {
  691.                 tmp = modf(integer / 10, &integer);
  692.                 *p-- = to_char((int)((tmp + .01) * 10));
  693.         }
  694.         switch (fmtch) {
  695.         case 'f':
  696.         case 'F':
  697.                 /* reverse integer into beginning of buffer */
  698.                 if (expcnt)
  699.                         for (; ++p < endp; *t++ = *p);
  700.                 else
  701.                         *t++ = '0';
  702.                 /*
  703.                  * if precision required or alternate flag set, add in a
  704.                  * decimal point.
  705.                  */
  706.                 if (prec || flags&ALT)
  707.                         *t++ = '.';
  708.                 /* if requires more precision and some fraction left */
  709.                 if (fract) {
  710.                         if (prec)
  711.                                 do {
  712.                                         fract = modf(fract * 10, &tmp);
  713.                                         *t++ = to_char((int)tmp);
  714.                                 } while (--prec && fract);
  715.                         if (fract) {
  716.                                 startp = round(fract, (int *)NULL, startp,
  717.                                     t - 1, (char)0, signp);
  718.                         }
  719.                 }
  720.                 for (; prec--; *t++ = '0');
  721.                 break;
  722.         case 'e':
  723.         case 'E':
  724. eformat:        if (expcnt) {
  725.                         *t++ = *++p;
  726.                         if (prec || flags&ALT)
  727.                                 *t++ = '.';
  728.                         /* if requires more precision and some integer left */
  729.                         for (; prec && ++p < endp; --prec)
  730.                                 *t++ = *p;
  731.                         /*
  732.                          * if done precision and more of the integer component,
  733.                          * round using it; adjust fract so we don't re-round
  734.                          * later.
  735.                          */
  736.                         if (!prec && ++p < endp) {
  737.                                 fract = 0;
  738.                                 startp = round((double)0, &expcnt, startp,
  739.                                     t - 1, *p, signp);
  740.                         }
  741.                         /* adjust expcnt for digit in front of decimal */
  742.                         --expcnt;
  743.                 }
  744.                 /* until first fractional digit, decrement exponent */
  745.                 else if (fract) {
  746.                         /* adjust expcnt for digit in front of decimal */
  747.                         for (expcnt = -1;; --expcnt) {
  748.                                 fract = modf(fract * 10, &tmp);
  749.                                 if (tmp)
  750.                                         break;
  751.                         }
  752.                         *t++ = to_char((int)tmp);
  753.                         if (prec || flags&ALT)
  754.                                 *t++ = '.';
  755.                 }
  756.                 else {
  757.                         *t++ = '0';
  758.                         if (prec || flags&ALT)
  759.                                 *t++ = '.';
  760.                 }
  761.                 /* if requires more precision and some fraction left */
  762.                 if (fract) {
  763.                         if (prec)
  764.                                 do {
  765.                                         fract = modf(fract * 10, &tmp);
  766.                                         *t++ = to_char((int)tmp);
  767.                                 } while (--prec && fract);
  768.                         if (fract)
  769.                                 startp = round(fract, &expcnt, startp,
  770.                                     t - 1, (char)0, signp);
  771.                 }
  772.                 /* if requires more precision */
  773.                 for (; prec--; *t++ = '0');
  774.  
  775.                 /* unless alternate flag, trim any g/G format trailing 0's */
  776.                 if (gformat && !(flags&ALT)) {
  777.                         while (t > startp && *--t == '0');
  778.                         if (*t == '.')
  779.                                 --t;
  780.                         ++t;
  781.                 }
  782.                 t = exponent(t, expcnt, fmtch);
  783.                 break;
  784.         case 'g':
  785.         case 'G':
  786.                 /* a precision of 0 is treated as a precision of 1. */
  787.                 if (!prec)
  788.                         ++prec;
  789.                 /*
  790.                  * ``The style used depends on the value converted; style e
  791.                  * will be used only if the exponent resulting from the
  792.                  * conversion is less than -4 or greater than the precision.''
  793.                  *      -- ANSI X3J11
  794.                  */
  795.                 if (expcnt > prec || (!expcnt && fract && fract < .0001)) {
  796.                         /*
  797.                          * g/G format counts "significant digits, not digits of
  798.                          * precision; for the e/E format, this just causes an
  799.                          * off-by-one problem, i.e. g/G considers the digit
  800.                          * before the decimal point significant and e/E doesn't
  801.                          * count it as precision.
  802.                          */
  803.                         --prec;
  804.                         fmtch -= 2;             /* G->E, g->e */
  805.                         gformat = 1;
  806.                         goto eformat;
  807.                 }
  808.                 /*
  809.                  * reverse integer into beginning of buffer,
  810.                  * note, decrement precision
  811.                  */
  812.                 if (expcnt)
  813.                         for (; ++p < endp; *t++ = *p, --prec);
  814.                 else
  815.                         *t++ = '0';
  816.                 /*
  817.                  * if precision required or alternate flag set, add in a
  818.                  * decimal point.  If no digits yet, add in leading 0.
  819.                  */
  820.                 if (prec || flags&ALT) {
  821.                         dotrim = 1;
  822.                         *t++ = '.';
  823.                 }
  824.                 else
  825.                         dotrim = 0;
  826.                 /* if requires more precision and some fraction left */
  827.                 if (fract) {
  828.                         if (prec) {
  829.                                 /* If no integer part, don't count initial
  830.                                  * zeros as significant digits. */
  831.                                 do {
  832.                                         fract = modf(fract * 10, &tmp);
  833.                                         *t++ = to_char((int)tmp);
  834.                                 } while(!tmp && !expcnt);
  835.                                 while (--prec && fract) {
  836.                                         fract = modf(fract * 10, &tmp);
  837.                                         *t++ = to_char((int)tmp);
  838.                                 }
  839.                         }
  840.                         if (fract)
  841.                                 startp = round(fract, (int *)NULL, startp,
  842.                                     t - 1, (char)0, signp);
  843.                 }
  844.                 /* alternate format, adds 0's for precision, else trim 0's */
  845.                 if (flags&ALT)
  846.                         for (; prec--; *t++ = '0');
  847.                 else if (dotrim) {
  848.                         while (t > startp && *--t == '0');
  849.                         if (*t != '.')
  850.                                 ++t;
  851.                 }
  852.         }
  853.         return (t - startp);
  854. }
  855.  
  856. #endif /* defined(FLOATING_POINT) && !defined(USE_DTOA) */
  857.  
  858. int streambuf::form(char const *format ...)
  859. {
  860.     va_list ap;
  861.     va_start(ap, format);
  862.     int count = vform(format, ap);
  863.     va_end(ap);
  864.     return count;
  865. }
  866.